/*
Copyright (C) 2015 Pieter Staal

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "river.h"
#include <SFML/Graphics.hpp>
#include <iostream>

using namespace sf;

int randint(int low, int high);

River::River(RiverSettings settings)
{
    this->position = settings.position;
    this->startPosition = settings.position;
    this->watermap = settings.watermap;
    this->normalizedHeightmap = settings.normalizedHeightmap;
    this->displayWatermap = settings.displayWatermap;
    this->riverCoordMod = settings.riverCoordMod;
    this->mapSize = settings.mapSize;
}


int River::flow()
{
    int x = position.x;
    int y = position.y;

    double heights[9];
    for (int hy = -1; hy <= 1; hy++)
    {
        for (int hx = -1; hx <= 1; hx++)
        {
            int heightIndex = (hx + 1) + (hy + 1) * 3;

            int mapX = (x + hx) * riverCoordMod;
            int mapY = (y + hy) * riverCoordMod;
            int heightMapIndex = mapX + mapY * mapSize;
            int waterMapIndex = (x + hx) + (y + hy) * (int)(mapSize / riverCoordMod);
            if (heightIndex != 4)
                heights[heightIndex] = watermap[waterMapIndex] ? 0 : normalizedHeightmap[heightMapIndex];
            else if (heightIndex == 4)
                heights[heightIndex] = normalizedHeightmap[heightMapIndex];
        }
    }
    //prevent rivers from crossing diagonally
    for (int sy = 1; sy <= 7; sy += 6)
    {
        for (int sx = 3; sx <= 5; sx += 2)
        {
            if (heights[sx] == 0 && heights[sy] == 0)
                heights[sy + (sx - 4)] = 0;
        }
    }

    int largestIndex = 0;
    for (int index = 0; index < 9; index++)
    {
        if (heights[index] >= heights[largestIndex])
        {
            largestIndex = index;
        }
    }
    int nextDirection = largestIndex;

    bool updateMaps = false;
    if (nextDirection != 4)
    {
        Vector2i newPosition = Vector2i(position.x + directions[nextDirection].x, position.y + directions[nextDirection].y);
        position = newPosition;
        generatorPath.push_back(nextDirection);
        totalPath.push_back(nextDirection);

        updateMaps = true;
        length++;
    }
    else if (nextDirection == 4)
    {
        //std::cout << rivers.at(i).stepBack() << "\n";
        totalPath.push_back((char)4);
        for (int steps = 0; steps < 4; steps++)
        {
            int direction = 8 - stepBack();

            Vector2i newPosition = Vector2i(position.x + directions[direction].x, position.y + directions[direction].y);
            position = newPosition;
            totalPath.push_back(direction);
        }

        branches++;
    }

    if (updateMaps)
    {
        watermap[position.x + position.y * (mapSize / riverCoordMod)] = true;
    }

    //std::cout << totalPath.size() << "\n";

    return nextDirection;
}

void River::drawOnMap()
{
    Vector2i drawPosition = startPosition;

    for (int i = 0; i < totalPath.size(); i++)
    {
        drawPosition = Vector2i(drawPosition.x + directions[totalPath.at(i)].x, drawPosition.y + directions[totalPath.at(i)].y);

        float resolution = 50;
        float lowestTransparency = 0.6;
        float depth = (resolution - i) / resolution;
        depth = depth < lowestTransparency ? lowestTransparency : depth;

        int riverWidth = 1;

        for (int t = 0; t < riverWidth; t++)
        {
            for (int j = 0; j <  riverCoordMod; j++)
            {
                int displayx = drawPosition.x * riverCoordMod - directions[totalPath.at(i)].x * j;
                int displayy = drawPosition.y * riverCoordMod - directions[totalPath.at(i)].y * j + t;
                displayWatermap[displayx + displayy * mapSize] = depth;
            }
        }
    }
}

void River::complete()
{
    int stuck = 0;

    while (stuck <= 3 && !completed)
    {
        if (flow() == 4)
            stuck++;
        else
            stuck = 0;
    }
    completed = true;
}

int River::stepBack()
{
    if (generatorPath.size() > branches + 2) // this value is not 0 to protect the first part of the river
    {
        int lastDirection = (int)(generatorPath.back());
        generatorPath.pop_back();
        return lastDirection;
    }
    else
    {
        return 4;
    }
}
